var widget = widget || { };
/**
 * Это класс виджета таблицы.
 * @lends widget.Grid
 */
widget.Grid = Base.extend({
	
	id : undefined,			// идентификатор объекта
	
	type : 'grid',			// тип объекта

	visible : true,			// признак того, что контейнер будет отображаться
	
	WIDGET_CLASS : 'wg_grid',
	
	entriesPerTableMsg : 'Show {select} entries',
	
	searchMsg : 'Search:',
	
	showingEntriesMsg : 'Showing _START_ to _END_ of _TOTAL_ entries',
	
	previousPageMsg : 'Previous',
	
	nextPageMsg : 'Next',

	allMsg : 'All',
	
	zeroRecordsMsg : 'No records to display',
	
	selectOptions : [10,15,20,30,50,-1],

	/**
	 * Конструктор класса
	 * @augments Base
	 * @class Класс виджета Таблица.
	 * <div><b>Используется:</b><br/>
	 * DataTables plug-in for the jQuery Javascript library.<br/>
	 * <a href="http://datatables.net/" target="_blank">http://datatables.net/</a>
	 * </div>
	 *
	 * <p><b>CSS класс для DOM элемента - <code>wg_grid</code></b></p>
	 * 
	 * <p><b>Параметры объекта конфигурации:</b></p>
	 * {String} <b>id</b> - Идентификатор таблицы.</br>
	 * {String} <b>cls</b> - Имя класса css (или нескольких классов через пробел)
	 * которые будут добавлены контейнеру.</br>
	 * {Int} <b>width</b> - Ширина таблицы.</br>
	 * {Int} <b>height</b> - Высота таблицы.</br>
	 * {Object[]} <b>data</b> - Массив строк таблицы [rows][cols].</br>
	 * {Object} <b>columns</b> - Объект описания колоник таблицы.</br>
	 * {ElementDOM} <b>renderTo</b> - Элемент DOM, в который будет прорисована таблица.</br>
	 * {Object[]} <b>listeners</b> - Массив слушателей событий.</br>
	 * 
	 * <p><b>События:</b></p>
	 * <b>afterrender</b> - Вызывается сразу после прорисовки таблицы.</br>
	 * <b>rowclick</b> - Вызывается при клике на область любой строки таблицы.</br>
	 * <b>hide</b> - Вызывается когда компонент был спрятан.</br>
	 * <b>show</b> - Вызывается когда компонент был показан.</br>
	 * 
	 * <p><b>Пример:</b></p>
	 * <pre class="code">
	 *  var usersData = [
	 *      ['1','Вася Пупкин'],
	 *      ['2','Петя Шапкин'],
	 *      ['3','Тарас Шевченко']
	 *  ];
	 *  
	 *  var usersColumns = [
	 *      { "sTitle": "",
	 *        "sClass": "center alignTop",
	 *        "sWidth": "20px",
	 *        "bSortable" : false,
	 *        "mRender": function (data, type, record) {
	 *            var id = record[0]
	 *            return '&lt;input id="x'+id+'" name="user" value="'+id+'" type="checkbox" /&gt;';
	 *        }
	 *      },
	 *      { "sTitle": "Имя пользователя",
	 *        "sClass": "left alignTop",
	 *        "bSortable" : true
	 *      }
	 *  ];
	 *
	 *  var contextMenu = new widget.PopupMenu({
	 *      width : 100,
	 *      cls : 'content',
	 *      items : [
	 *          { value:1, text:'Детали'},
	 *          { value:2, text:'Правка'},
	 *          { value:4, text:'Удалить'}
	 *      ],
	 *      listeners : {
	 *          select : function(menu, menuItem, gridRecord){
	 *              alert('Выбрано "'+menuItem.text+'" для строки с id='+gridRecord[0]);
	 *          }
	 *      }
	 *  });
	 *  
	 *  var grid = new widget.Grid({
	 *      id : 'grid1',
	 *      cls : 'display',
	 *      data : data,
	 *      columns : columns,
	 *      countEntries : [5,7,10,15,20],
	 *      contextMenu : contextMenu,
	 *      renderTo : $('#grid_holder'),
	 *      listeners : {
	 *          rowclick : function(record, elementDom, event){
	 *              alert('Выбрана запись с ID='+record[0]+' от '+record[1]);
	 *          }
	 *      }
	 *  });
	 * </pre>
	 * 
	 * @constructs
	 * @param {Object} config Конфигурационный объект компонента.
	 * @param {String} config.id Идентификатор компонента.
	 * @param {String} config.cls Имя класса css (или нескольких классов через пробел)
	 * которые будут добавлены контейнеру.
	 * @param {Int} config.width Ширина компонента.
	 * @param {Int} config.height Высота компонента.
	 * @param {Object[]} config.items Массив компонент, которые должны быть включены в контейнер.
	 * @param {boolean} config.scrolling Признак того, что элементы внутри контейнера могут 
	 * скролироваться, если сумма высот всех входящих элементов больше высоты контейнера.
	 * @param {ElementDOM} config.renderTo Элемент DOM, в который будет прорисован контейнер.</br>
	 * @param {Object[]} config.listeners Массив слушателей событий
	 */
	constructor : function(config) {
		this.tabs = [];
		this.config = config || {} ;
		this.id = (config.id)? config.id : this.WIDGET_CLASS+this.generateId();
		this.config.id = this.id;
		this.selectOptions = [10,15,20,30,50,-1];
		if (this.config.renderTo) {
			try {
				this.render(this.config.renderTo);
			} catch (e) {
				var msg = 'widget.Grid::render(): ' + e;
				console.log("- Exception: ",msg);
				throw msg;
			}
		}
	},
	
	/**
	 * Эта функция возвращает идентификатор контейнера
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 * @return {string} - идентификатор контейнера
	 */
	getId : function() {
		return this.id;
	},
	
	/**
	 * Эта функция возвращает тип объекта
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 * @return {string} - тип объекта
	 */
	getType : function() {
		return this.type;
	},
	
	/**
	 * Возвращает признак видимости компонента закладок.
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 * @return {boolean} - true, если объект видимый. Иначе false.
	 */
	isVisible : function() {
		return this.visible;
	},
	
	/**
	 * Установить признак видимости поля.
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 * @param {boolean} visible признак доступности объекта.
	 * @return none
	 */
	setVisible : function(visible) {
		this.visible = visible;
	},
	
    /**
     * @private 
	 * @function
     * This function generate unique id using date-time, math round operation, reverse string
     * by length=10 chars
     * @return {string} id
    */
    generateId : function() {    
        return Math.round(((new Date()).getTime()+Math.random())*100).toString().split('').reverse().join('').substr(0,10);
    },

	/**
	 * Выполняется отрисовка закладок.
     * @private 
	 * @function
	 * @param (elementDOM) renderTo Элемент DOM, внутри которого будет создан контейнер.
	 * @return none
	 */
	render : function(renderTo) {

		var me = this;
		
		if (renderTo) {
			this.renderContainer = renderTo;
		} else {
			renderTo = this.renderContainer;
		}

		var tpl = '<table cellpadding="0" cellspacing="0" border="0" class="' +
			this.WIDGET_CLASS+'" id="' + this.getId() + ' id="example"></table>'
		
		if (this.element) {
			this.element.remove();
		}
		this.element = $(tpl);
		
		this.applyConfigToElement(this.config, this.element);
				 
		if (renderTo) {
			$(this.element).appendTo(renderTo);
			$(this.element).click(function() {
				me.onClick();
			});

			var gridParams = {};
			if (this.config.data) {
				gridParams.aaData = this.config.data;
			}
			if (this.config.initAjax) {
				gridParams.bServerSide = true;
				gridParams.sAjaxSource = this.config.initAjax.url;
				gridParams.sQuery = this.config.initAjax.query;
				gridParams.bProcessing = true;
				gridParams.sServerMethod = "POST";
			}
			gridParams.aoColumns = this.config.columns;
			gridParams.oLanguage = gridParams.oLanguage || {};
			var select = '<select>';
			var arr = (this.config.countEntries)? this.config.countEntries : this.selectOptions;
			for (var i=0; i<arr.length; i++) {
				select += '<option value="' + arr[i] + '"';
				if (this.config.countEntry == arr[i]) {
					select += ' selected';
				} 
				select += '>' + 
						((arr[i] == -1)? this.allMsg : arr[i]) + '</option>';
				
			}
			select += '/<select>';
			gridParams.oLanguage.sLengthMenu = this.entriesPerTableMsg.format({
				"select": select
			});
			gridParams.oLanguage.sSearch = this.searchMsg;
			gridParams.oLanguage.sInfo = this.showingEntriesMsg;
			gridParams.oLanguage.oPaginate = gridParams.oLanguage.oPaginate || {};
			gridParams.oLanguage.oPaginate.sNext = this.nextPageMsg;
			gridParams.oLanguage.oPaginate.sPrevious = this.previousPageMsg;
			gridParams.oLanguage.sZeroRecords = this.zeroRecordsMsg;
			
			gridParams.fnRowCallback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
				$(nRow).click(function(event) {
					me.onRowClick(aData, nRow, event);
					//event.preventDefault();
				});

				$(nRow).bind('contextmenu', function(event) {
console.log('- 1');
					me.onContextMenu(aData, nRow, event);
					return false;
				});
			}
						
			this.element.dataTable(gridParams);
			
			this.onAfterRender();
		}
	},
	
	/**
	 * Выполняется перерисовка одной или всех закладок.
     * @public 
     * @function 
     * @memberOf widget.Grid#
     * @param {Integer} tabIndex Необязательный параметр, указывающий какую 
     * закладку надо перерисовать. Если не указан, перерисовываюься все закладки.
	 */
	refresh : function(tabIndex) {
		if (this.renderContainer) {
			if (tabIndex == undefined) {
				for (var i=0; i<this.tabs.length; i++) {
					this.tabs[i].refresh();
				}
			} else {
				this.tabs[tabIndex].refresh();
			}
		}
	},
	
	/**
	 * Функция реализовывает атрибуты объекта config.
	 * Атрибуты: width, height, cls
     * @private 
	 */
	applyConfigToElement : function(config, element) {
		if (config.width) {
			element.width(config.width);
		}
		if (config.height) {
			element.height(config.height);
		}
		
		if (config.cls) {
			var arr = config.cls.split(' ');
			for (var i=0; i<arr.length; i++) {
				$(element).addClass(arr[i]);
			}
		}
	},
	
	/**
	 * Функция отрабатывает сразу после клика мышки на строке таблицы.
     * @private 
	 * @function
	 */
	onRowClick : function(record, element, event) {
		if (this.config.listeners && this.config.listeners.rowclick) {
			this.config.listeners.rowclick(record, element, event);
		}
	},

	/**
	 * Функция отрабатывает сразу после клика правой клавиши мышки на строке таблицы.
     * @private 
	 * @function
	 */
	onContextMenu : function(record, element, event) {
		var menu = this.config.contextMenu;
		if (menu && menu.config.listeners && menu.config.listeners.select) {
			var position = { x : event.pageX, y : event.pageY };
			menu.render(position, record);
		}
	},

	/**
	 * Функция отрабатывает сразу после прорисовки конпонента. 
     * @private 
	 * @function
	 */
	onAfterRender : function() {
		if (this.config.listeners && this.config.listeners.afterrender) {
			this.config.listeners.afterrender(this, this.element);
		}
	},
	
	/**
	 * Функция отрабатывает сразу после клика мышки на компоненте. 
     * @private 
	 * @function
	 */
	onClick : function() {
		if (this.config.listeners && this.config.listeners.click) {
			this.config.listeners.click(this, this.element);
		}
	},
	
	/**
	 * Спрятать закладки 
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 */
	hide : function() {
		var oldVisible = this.visible; 
		this.visible = false;
		if (this.visible != oldVisible) {
			this.element.addClass("hidden");
			this.onHide();
		}
	},
	
	/**
	 * Показать закладки 
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 */
	show : function() {
		var oldVisible = this.visible; 
		this.visible = true;
		if (this.visible != oldVisible) {
			this.element.removeClass("hidden");
			this.onShow();
		}
	},
	
	/**
	 * Удалить закладки 
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 */
	remove : function() {
		this.element.remove();
		this.onRemove();
	},
	
	/**
	 * Открыть вкладку, согласно указанному индексу.
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 */
	selectTabByIndex : function(index) {
		this.element.tabs({selected : index});
		this.onChange(index);
	},
	
	/**
	 * Функция отрабатывает сразу после выбора вкладки. 
     * @private 
	 * @function
	 */
	onChange : function(index) {
		if (index != this.selectedTabIndex) {
			this.selectedTabIndex = index; 
			if (this.config.listeners && this.config.listeners.change) {
				this.config.listeners.change(this, index, this.tabs[index], this.element);
			}
		}
	},
	
	/**
	 * Функция отрабатывает после того, как элемент будет спрятан. 
     * @private 
	 * @function
	 */
	onHide : function() {
		if (this.config.listeners && this.config.listeners.hide) {
			this.config.listeners.hide(this, this.element);
		}
	},
	
	/**
	 * Функция отрабатывает после того, как элемент будет показан. 
     * @private 
	 * @function
	 */
	onShow : function() {
		if (this.config.listeners && this.config.listeners.show) {
			this.config.listeners.show(this, this.element);
		}
	},
	
	/**
	 * Функция отрабатывает после того, как элемент будет удален. 
     * @private 
	 * @function
	 */
	onRemove : function() {
		if (this.config.listeners && this.config.listeners.remove) {
			this.config.listeners.remove(this, this.element);
		}
	},
	
	/**
	 * Получить представление объекта в виде строки.
     * @public 
	 * @function
     * @memberOf widget.Grid#
	 */
	toString : function() {
		return 'widget.control.Grid:{"'+this.getType()+'":{"id":"'+this.getId()+'"}}'
	}

});
